using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;

using Framework;

namespace SchemaMonitor
{
    [Serializable()]
    public partial class CPhotoHashList : List<CPhotoHash>
    {
        #region Constructors
        //Basic constructor
        public CPhotoHashList() : base() {}
       
        //More efficient memory-allocation if size is known
        public CPhotoHashList(int capacity) : base(capacity) {}
        
        //Shares the index (if its already been computed)
        public CPhotoHashList(CPhotoHashList list) : base(list.Count)
        {
            foreach (CPhotoHash i in list)
                base.Add(i);
        }

        //Generic list (eg. from paging control), have to assume type
        public CPhotoHashList(IList list) : base(list.Count)
        {
            foreach (CPhotoHash i in list)
                base.Add(i);
        }
        #endregion
        
        #region Top/Bottom/Page
        public CPhotoHashList Top(int count)
        {
            if (count >= this.Count)
                return this;
            return Page(count, 0); 
        }
        public CPhotoHashList Bottom(int count)   
        {
            if (count > this.Count)
                count = this.Count;
            return new CPhotoHashList(this.GetRange(this.Count - count - 1, count));
        }
        public CPhotoHashList Page(int pageSize, int pageIndex)
        {
            return new CPhotoHashList( CUtilities.Page(this, pageSize, pageIndex) );
        }
        #endregion

        #region BulkEditLogic
        public bool HaveSameValue(string propertyName)               { return CReflection.HaveSameValue(this, propertyName); }
        public void SetSameValue( string propertyName, object value) {        CReflection.SetSameValue( this, propertyName, value); }
        #endregion

        #region SortBy
        //Public
        public CPhotoHashList SortBy(string propertyName) { return SortBy(propertyName, false); }
        public CPhotoHashList SortBy(string propertyName, bool descending)
        {
            CPhotoHashList copy = new CPhotoHashList(this);
            if (this.Count == 0)    return copy;
            copy.Sort(new CPhotoHashList_SortBy(propertyName, descending, this));
            return copy;
        }
        //Private 
        private class CPhotoHashList_SortBy : CReflection.GenericSortBy, IComparer<CPhotoHash>
        {
            public CPhotoHashList_SortBy(string propertyName, bool descending, IList list) : base(propertyName, descending, list) { }
            public int Compare(CPhotoHash x, CPhotoHash y) { return base.Compare(x, y); }
        }
        #endregion

        #region SaveAll/DeleteAll
        //Use default connection (may be overridden in base class)
        public void SaveAll()   {   if (this.Count > 0) { SaveAll(  this[0].DataSrc);    }    }
        public void DeleteAll() {   if (this.Count > 0) { DeleteAll(this[0].DataSrc);    }    }

        //Use connection supplied
        public void SaveAll(  CDataSrc dataSrc) {   dataSrc.BulkSave(this);    }
        public void DeleteAll(CDataSrc dataSrc) {   dataSrc.BulkDelete(this);  }

        //Use transaction supplied
        public void SaveAll(  IDbTransaction txOrNull)    {   foreach (CPhotoHash i in this) {   i.Save(  txOrNull);   }   }
        public void DeleteAll(IDbTransaction txOrNull)    {   foreach (CPhotoHash i in this) {   i.Delete(txOrNull);   }   }

        //Use a specified isolation level
        public void SaveAll(  IsolationLevel txIsolationLevel)   {   if (this.Count > 0) { SaveAll(  this[0].DataSrc, txIsolationLevel);  }    }
        public void DeleteAll(IsolationLevel txIsolationLevel)   {   if (this.Count > 0) { DeleteAll(this[0].DataSrc, txIsolationLevel);  }    }

        //Use a specified connection and isolation level
        public void SaveAll(  CDataSrc dataSrc, IsolationLevel txIsolationLevel)   {   dataSrc.BulkSave(  this, txIsolationLevel);  }
        public void DeleteAll(CDataSrc dataSrc, IsolationLevel txIsolationLevel)   {   dataSrc.BulkDelete(this, txIsolationLevel);  }
        #endregion

        #region List of Ids
        List<Guid> _ids;
        public List<Guid> Ids
        {
            get
            {
                if (null == _ids)
                {
                    List<Guid> ids = new List<Guid>(this.Count);
					foreach (CPhotoHash i in this)
						if (null != i)
							ids.Add(i.PhotoMd5);
						else
							Console.WriteLine(string.Concat("Missing photo #", this.IndexOf(i) + 1, " of ", this.Count));
                    _ids = ids;
                }
                return _ids;
            }
        }
        public CPhotoHashList GetByIds(List<Guid> ids)
        {
            CPhotoHashList list = new CPhotoHashList(ids.Count);
            foreach (Guid id in ids)
                if (null != GetById(id))
                    list.Add(GetById(id));
            return list;
        }
        #endregion
        
        #region Cache-Control
        //Main Logic

    
        //Supplementary List Overloads
        public void Add(   IList<CPhotoHash> itemsToAdd)    {   foreach (CPhotoHash i in itemsToAdd)   { Add(   i); }   }
        public void Remove(IList<CPhotoHash> itemsToRemove) {   foreach (CPhotoHash i in itemsToRemove){ Remove(i); }   }
        #endregion
        
            
        #region Foreign-Key Indices (Subsets)
        //Index by PhotoThumbMD5
        public CPhotoHashList GetByThumbMD5(Guid thumbMD5)
        {
            CPhotoHashList temp = null;
            if (! IndexByThumbMD5.TryGetValue(thumbMD5, out temp))
            {
                temp = new CPhotoHashList();
                IndexByThumbMD5[thumbMD5] = temp;
            }
            return temp;
        }

        [NonSerialized]
        private Dictionary<Guid, CPhotoHashList> _indexByThumbMD5;
        private Dictionary<Guid, CPhotoHashList> IndexByThumbMD5
        {
            get
            {
                if (null == _indexByThumbMD5)
                {
                    Dictionary<Guid, CPhotoHashList> index = new Dictionary<Guid, CPhotoHashList>();
                    CPhotoHashList temp = null;
                    foreach (CPhotoHash i in this)
                    {
                        if (! index.TryGetValue(i.PhotoThumbMD5, out temp))
                        {
                            temp = new CPhotoHashList();
                            index[i.PhotoThumbMD5] = temp;
                        }
                        temp.Add(i);
                    }
                    _indexByThumbMD5 = index;
                }
                return _indexByThumbMD5;
            }
        }

		//Index by PhotoParentMD5
		public CPhotoHashList GetByParentMD5(Guid parentMD5)
		{
			CPhotoHashList temp = null;
			if (!IndexByParentMD5.TryGetValue(parentMD5, out temp))
			{
				temp = new CPhotoHashList();
				IndexByParentMD5[parentMD5] = temp;
			}
			return temp;
		}

		[NonSerialized]
		private Dictionary<Guid, CPhotoHashList> _indexByParentMD5;
		private Dictionary<Guid, CPhotoHashList> IndexByParentMD5
		{
			get
			{
				if (null == _indexByParentMD5)
				{
					Dictionary<Guid, CPhotoHashList> index = new Dictionary<Guid, CPhotoHashList>();
					CPhotoHashList temp = null;
					foreach (CPhotoHash i in this)
					{
						if (!index.TryGetValue(i.PhotoParentMD5, out temp))
						{
							temp = new CPhotoHashList();
							index[i.PhotoParentMD5] = temp;
						}
						temp.Add(i);
					}
					_indexByParentMD5 = index;
				}
				return _indexByParentMD5;
			}
		}

		public CPhotoHashList GetByTag(CMetaTag t) { return GetByLabel(t); }
        public CPhotoHashList GetByNot(CMetaTag t)
        {
            return this.Except(this.GetByTag(t));
        }
        public CPhotoHashList GetByLabel(CMetaTag t)
        {
            var temp = new CPhotoHashList();
            if (t.TagType.TagIsOneToOne)
			    foreach (var i in this)
				    if ( i.Label_OneToOnes.GetByTagId(t.TagId).Count > 0)
					    temp.Add(i);

            if (!t.TagType.TagIsOneToOne)
                foreach (var i in this)
                    if (i.Labels.GetByTagId(t.TagId).Count > 0)
                        temp.Add(i);
			return temp;
		}
		#endregion

	}
}
